/**
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */
import { computed, defineComponent, ref, SetupContext } from "vue";
import { datePickerContainerProps, DatePickerContainerProps } from "./date-picker-container.props";
import FCalenderNavBar from '../calendar-navbar/calendar-navbar.component';
import CalenderView from '../calendar/calendar.component';
import MonthView from '../month/month.component';
import YearView from '../year/year.component';
import { useDisableDate } from "../../composition/use-disable-date";
import { UseDisableDate } from "../../composition/types";
import useCalendar from "../../composition/use-calendar";
import { DateObject } from "../../types/common";
import { useDate } from "../../composition/use-date";
import { ActiveMonth } from "../../types/month";
import { useMonth } from "../../composition/use-month";
import { useYear } from "../../composition/use-year";

import './date-picker-container.css';

export default defineComponent({
    name: 'FDatePickerContainer',
    props: datePickerContainerProps,
    emits: ['datePicked'] as (string[] & ThisType<void>) | undefined,
    setup(props: DatePickerContainerProps, context: SetupContext) {

        const top = ref<number>(props.top);
        const left = ref<number>(props.left);
        const position = ref<string>(props.position);
        const enablePeriod = ref(props.enablePeriod);
        const selectMode = ref(props.selectMode);
        const dateFormat = ref(props.dateFormat);
        // const years = ref(props.years);
        const nameOfMonths = ref<any>(props.nameOfMonths);
        const secondaryYears = ref<any[]>([]);
        const selectingMonth = ref(false);
        const selectingSecondaryMonth = ref('');
        const selectingYear = ref(false);
        const selectingSecondaryYear = ref('');
        const selectTime = ref();
        const disablePrePage = ref(false);
        const disablePreRecord = ref(false);
        const disableNextRecord = ref(false);
        const disableNextPage = ref(false);
        const disableSecondaryPrePage = ref(false);
        const disableSecondaryPreRecord = ref(false);
        const disableSecondaryNextRecord = ref(false);
        const disableSecondaryNextPage = ref(false);
        // const dates = ref(props.dates);
        const secondaryDates = ref(props.secondaryDates);
        const daysInWeek = ref(props.daysInWeek);
        const enableKeyboadNavigate = ref(props.enableKeyboadNavigate);
        const enableMarkCurrent = ref(props.enableMarkCurrent);
        const firstDayOfTheWeek = ref(props.firstDayOfTheWeek);
        const showWeekNumber = ref(props.showWeekNumber);
        const selectedDate = ref<DateObject>(props.selectedDate);
        const selectedWeek = ref(props.selectedWeek);
        const selectedPeriod = ref(props.selectedPeriod);
        const weekTitle = ref(props.weekTitle);
        // const months = ref(props.months);
        const secondaryMonths = ref(props.secondaryMonths);
        const selectedMonth = ref<DateObject>(props.selectedMonth);
        const minYear = ref(props.minYear);
        const maxYear = ref(props.maxYear);
        const disableSince = ref(props.disableSince);
        const disableUntil = ref(props.disableUntil);
        const disableDates = ref(props.disableDates);
        const disablePeriod = ref(props.disablePeriod);
        const disableWeekdays = ref(props.disableWeekdays);
        const disableWeekends = ref(props.disableWeekends);

        const refDisableDate: UseDisableDate = useDisableDate(
            minYear.value,
            maxYear.value,
            disableSince.value,
            disableUntil.value,
            disableDates.value,
            disablePeriod.value,
            disableWeekends.value,
            disableWeekdays.value
        );

        const { generateCalendar } = useCalendar(refDisableDate);
        const { getToday } = useDate();
        const { generateMonths, getNextMonth, getPreviousMonth } = useMonth();
        const { generateYears } = useYear();

        const today = getToday();
        const activeMonth = ref<ActiveMonth>({
            year: today.year || 1,
            month: today.month || 1,
            displayTextOfMonth: nameOfMonths.value[today.month || '1'],
            displayTextOfYear: `${today.year}`
        });
        const initSecondaryYear = today.month === 12 ? (today.year || 1) + 1 : today.year;
        const initSecondaryMonth = (today.month || 1) < 12 ? (today.month || 1) + 1 : 1;
        const secondaryActiveMonth = ref({
            year: initSecondaryYear,
            month: initSecondaryMonth,
            displayTextOfMonth: nameOfMonths.value[today.month || '1'],
            displayTextOfYear: `${initSecondaryYear}`
        });

        const dates = computed(() => {
            const weekItems = generateCalendar(
                activeMonth.value.month,
                activeMonth.value.year,
                firstDayOfTheWeek.value,
                [],
                { marked: true, color: '' },
                [],
                props.highlightSaturday,
                props.highlightSunday,
                showWeekNumber.value);
            return weekItems;
        });

        const months = computed(() => {
            const monthViewItems = generateMonths(
                nameOfMonths.value,
                { year: activeMonth.value.year, month: activeMonth.value.month },
                disableSince.value,
                disableUntil.value
            );
            return monthViewItems;
        });

        const years = computed(() => {
            const yearViewItems = generateYears(
                activeMonth.value.year,
                { year: activeMonth.value.year, month: activeMonth.value.month },
                minYear.value,
                maxYear.value,
                disableSince.value,
                disableUntil.value
            );
            return yearViewItems;
        });

        const containerClass = computed(() => {
            const classObject = {
                'f-datepicker-container': true
            } as Record<string, boolean>;
            const className = `container-position-${position.value}`;
            classObject[className] = true;
            return classObject;
        });

        function getWidth() { return ''; };

        const containerStyle = computed(() => {
            const styleObject = {
                'top': `${top.value}px`,
                'left': `${left.value}px`,
                'width': getWidth()
            } as Record<string, any>;
            return styleObject;
        });

        function onCloseSelector($event: KeyboardEvent) { }

        function onClickContainer($event: MouseEvent) {
            $event.stopPropagation();
        }

        function navigateToPreviousPage($event: any, inPeriod: boolean) {
            const previousYear = activeMonth.value.year - (selectingYear.value ? 10 : 1);
            const previous = {
                year: previousYear,
                month: activeMonth.value.month,
                displayTextOfMonth: nameOfMonths.value[activeMonth.value.month || '1'],
                displayTextOfYear: `${previousYear}`
            };
            activeMonth.value = previous;
        }

        function navigateToPreviousMonth($event: any, inPeriod: boolean) {
            const previousMonthDate = getPreviousMonth(activeMonth.value.month, activeMonth.value.year);
            const previous = {
                year: previousMonthDate.year || 1,
                month: previousMonthDate.month || 1,
                displayTextOfMonth: nameOfMonths.value[previousMonthDate.month || '1'],
                displayTextOfYear: `${previousMonthDate.year}`
            };
            activeMonth.value = previous;
        }

        function navigateToNextMonth($event: any, inPeriod: boolean) {
            const nextMonthDate = getNextMonth(activeMonth.value.month, activeMonth.value.year);
            const next = {
                year: nextMonthDate.year || 1,
                month: nextMonthDate.month || 1,
                displayTextOfMonth: nameOfMonths.value[nextMonthDate.month || '1'],
                displayTextOfYear: `${nextMonthDate.year}`
            };
            activeMonth.value = next;
        }

        function navigateToNextPage($event: any, inPeriod: boolean) {
            const nextYear = activeMonth.value.year + 1;
            const next = {
                year: nextYear,
                month: activeMonth.value.month,
                displayTextOfMonth: nameOfMonths.value[activeMonth.value.month || '1'],
                displayTextOfYear: `${nextYear}`
            };
            activeMonth.value = next;
        }

        function navigateToMonthView(inPeriod: boolean) {
            selectingMonth.value = true;
            selectingYear.value = false;
        }

        function navigateToYearView(inPeriod: boolean) {
            selectingMonth.value = false;
            selectingYear.value = true;
        }

        const primaryCalendarNavBarProps = computed(() => {
            return {
                'active-month': activeMonth.value,
                'date-format': dateFormat.value,
                'disable-pre-page': disablePrePage.value,
                'disable-pre-record': disablePreRecord.value,
                'disable-next-record': disableNextRecord.value,
                'disable-next-page': disableNextPage.value,
                'years': years.value,
                'selecting-month': selectingMonth.value,
                'selecting-year': selectingYear.value,
                'select-mode': selectMode.value
            };
        });

        const secondaryCalendarNavBarProps = computed(() => {
            return {
                'active-month': secondaryActiveMonth.value,
                'date-format': dateFormat.value,
                'disable-pre-page': disableSecondaryPrePage.value,
                'disable-pre-record': disableSecondaryPreRecord.value,
                'disable-next-record': disableSecondaryNextRecord.value,
                'disable-next-page': disableSecondaryNextPage.value,
                'years': secondaryYears.value,
                'selecting-month': selectingSecondaryMonth.value,
                'selecting-year': selectingSecondaryYear.value,
                'select-mode': selectMode.value
            };
        });

        function renderNavBar(inPeriod: boolean, calendarNavBarProps: any) {
            return (
                <FCalenderNavBar {...calendarNavBarProps}
                    onPrePage={($event: any) => navigateToPreviousPage($event, inPeriod)}
                    onPreRecord={($event: any) => navigateToPreviousMonth($event, inPeriod)}
                    onNextRecord={($event: any) => navigateToNextMonth($event, inPeriod)}
                    onNextPage={($event: any) => navigateToNextPage($event, inPeriod)}
                    onClickMonth={($event: any) => navigateToMonthView(inPeriod)}
                    onClickYear={($event: any) => navigateToYearView(inPeriod)}
                ></FCalenderNavBar>
            );
        }

        const shouldShowCalendarView = computed(() => {
            return (!selectingMonth.value && !selectingYear.value && !selectTime.value) ||
                (enablePeriod.value && selectMode.value !== 'week' && !selectingSecondaryMonth.value
                    && !selectingSecondaryYear.value && !selectTime.value);
        });

        const shouldShowMonthView = computed(() => {
            return selectingMonth.value && !selectingYear.value;
        });

        const shouldShowYearView = computed(() => {
            return selectingYear.value && !selectingMonth.value;
        });

        const primaryCalendarProps = computed(() => {
            return {
                dates: dates.value,
                daysInWeek: daysInWeek.value,
                enableKeyboadNavigate: enableKeyboadNavigate.value,
                enableMarkCurrent: enableMarkCurrent.value,
                enablePeriod: enablePeriod.value,
                firstDayOfTheWeek: firstDayOfTheWeek.value,
                selected: selectedDate.value,
                selectedPeriod: selectedPeriod.value,
                selectedWeek: selectedWeek.value,
                selectMode: selectMode.value,
                showWeekNumber: showWeekNumber.value,
                weekTitle: weekTitle.value
            };
        });

        const secondaryCalendarProps = computed(() => {
            return {
                dates: secondaryDates,
                daysInWeek: daysInWeek.value,
                enableKeyboadNavigate: enableKeyboadNavigate.value,
                enableMarkCurrent: enableMarkCurrent.value,
                enablePeriod: enablePeriod.value,
                firstDayOfTheWeek: firstDayOfTheWeek.value,
                selected: selectedDate.value,
                selectedPeriod: selectedPeriod.value,
                selectMode: showWeekNumber.value,
                showWeekNumber: showWeekNumber.value,
                weekTitle: weekTitle.value
            };
        });

        function onClickDay(currentDate: DateObject, isPeriod: boolean) {
            selectedDate.value = currentDate;
            context.emit('datePicked', `${currentDate.year}-${currentDate.month}-${currentDate.day}`);
        }

        function onClickWeek($event: any) { }

        function onKeyDownCalendar($event: any) { }

        function onMouseEnterCalendar($event: any, isPeriod: boolean) { }

        function onMouseLeaveCalendar($event: any, isPeriod: boolean) { }

        function renderCalender(inPeriod: boolean, calendarProps: any) {
            return shouldShowCalendarView.value &&
                <CalenderView {...calendarProps}
                    onClick={(payload: any) => onClickDay(payload, inPeriod)}
                    onClickWeek={(payload: any) => onClickWeek(payload)}
                    onKeyDown={(payload: any) => onKeyDownCalendar(payload)}
                    onMouseEnter={(payload: any) => onMouseEnterCalendar(payload, inPeriod)}
                    onMouseLeave={(payload: any) => onMouseLeaveCalendar(payload, inPeriod)}
                ></CalenderView>;
        };

        const monthProps = computed(() => {
            return {
                months: months.value,
                enableMarkCurrent: enableMarkCurrent.value,
                enableKeyboadNavigate: enableKeyboadNavigate.value,
                enablePeriod: enablePeriod.value,
                selected: selectedMonth.value,
                selectedPeriod: selectedPeriod.value
            };
        });

        const secondMonthProps = computed(() => {
            return {
                months: secondaryMonths.value,
                enableMarkCurrent: enableMarkCurrent.value,
                enableKeyboadNavigate: enableKeyboadNavigate.value,
                enablePeriod: enablePeriod.value,
                selected: selectedMonth.value,
                selectedPeriod: selectedPeriod.value
            };
        });

        function onClickMonth(currentMonth: DateObject, isPeriod: boolean) {
            selectingMonth.value = false;
            selectingYear.value = false;
            selectedMonth.value = currentMonth;
            activeMonth.value = {
                month: currentMonth.month || 1,
                displayTextOfMonth: nameOfMonths.value[activeMonth.value.month || '1'],
                year: activeMonth.value.year || 1,
                displayTextOfYear: `${activeMonth.value.displayTextOfYear}`
            };
        }

        function onKeyDownMonthView($event: any) { }

        function onMouseEnterMonthView($event: any, isPeriod: boolean) { }

        function onMouseLeaveMonthView($event: any, isPeriod: boolean) { }

        function renderMonth(inPeriod: boolean, monthProps: any) {
            return <MonthView {...monthProps}
                onClick={(payload: any) => onClickMonth(payload, inPeriod)}
                onKeyDownMonthView={(payload: any) => onKeyDownMonthView(payload)}
                onMouseEnterMonthView={(payload: any) => onMouseEnterMonthView(payload, inPeriod)}
                onMouseLeaveMonthView={(payload: any) => onMouseLeaveMonthView(payload, inPeriod)}
            ></MonthView >;
        }

        const yearProps = computed(() => {
            return {
                years: years.value,
                enableKeyboadNavigate: enableKeyboadNavigate.value,
                enableMarkCurrent: enableMarkCurrent.value,
                enablePeriod: enablePeriod.value,
                selected: selectedDate.value,
                selectedPeriod: selectedPeriod.value
            };
        });

        const secondYearProps = computed(() => {
            return {
                years: secondaryYears.value,
                enableKeyboadNavigate: enableKeyboadNavigate.value,
                enableMarkCurrent: enableMarkCurrent.value,
                enablePeriod: enablePeriod.value,
                selected: selectedDate.value,
                selectedPeriod: selectedPeriod.value
            };
        });

        function onClickYear(currentYear: DateObject, isPeriod: boolean) {
            selectingMonth.value = true;
            selectingYear.value = false;
            activeMonth.value = {
                month: activeMonth.value.month,
                displayTextOfMonth: activeMonth.value.displayTextOfMonth,
                year: currentYear.year || 1,
                displayTextOfYear: `${currentYear.year}`
            };
        }

        function onKeyDownYearView($event: any) { }

        function onMouseEnterYearView($event: any, isPeriod: boolean) { }

        function onMouseLeaveYearView($event: any, isPeriod: boolean) { }

        function navigateToToday($event: MouseEvent) {
            activeMonth.value = {
                year: today.year || 1,
                month: today.month || 1,
                displayTextOfMonth: nameOfMonths.value[today.month || '1'],
                displayTextOfYear: `${today.year}`
            };
            selectedDate.value = today;
        }

        function navigateToCurrentMonth($event: MouseEvent) {
            activeMonth.value = {
                year: today.year || 1,
                month: today.month || 1,
                displayTextOfMonth: nameOfMonths.value[today.month || '1'],
                displayTextOfYear: `${today.year}`
            };
            selectedDate.value = today;
            selectedMonth.value = { year: today.year, month: today.month };
        }

        function navigateToCurrentYear($event: MouseEvent) {
            activeMonth.value = {
                year: today.year || 1,
                month: today.month || 1,
                displayTextOfMonth: nameOfMonths.value[today.month || '1'],
                displayTextOfYear: `${today.year}`
            };
            selectedDate.value = today;
        }

        const shouldShowSecondCalendar = computed(() => {
            return enablePeriod.value && selectMode.value !== 'week';
        });

        function renderYear(inPeriod: boolean, yearProps: any) {
            return <YearView {...yearProps}
                onClick={(payload: any) => onClickYear(payload, inPeriod)}
                onKeyDownYearView={(payload: any) => onKeyDownYearView(payload)}
                onClickPreRecord={(payload: any) => navigateToPreviousMonth(payload, inPeriod)}
                onClickNextRecord={(payload: any) => navigateToNextMonth(payload, inPeriod)}
                onMouseEnterYearView={(payload: any) => onMouseEnterYearView(payload, inPeriod)}
                onMouseLeaveYearView={(payload: any) => onMouseLeaveYearView(payload, inPeriod)}
            ></YearView >;
        }

        return () => {
            return (
                <div class={containerClass.value} style={containerStyle.value} tabindex="0"
                    onKeyup={(payload: KeyboardEvent) => onCloseSelector(payload)}
                    onClick={(payload: MouseEvent) => onClickContainer(payload)}>
                    <div class="f-datepicker-content">
                        {renderNavBar(false, primaryCalendarNavBarProps.value)}
                        {renderCalender(false, primaryCalendarProps.value)}
                        {selectingMonth.value && renderMonth(false, monthProps.value)}
                        {selectingYear.value && renderYear(false, yearProps.value)}
                        <div class="f-datepicker-footer">
                            <div class="f-datepicker-redirect">
                                {shouldShowCalendarView.value && <button class="btn btn-link" onClick={navigateToToday}>今天</button>}
                                {shouldShowMonthView.value && <button class="btn btn-link" onClick={navigateToCurrentMonth}>本月</button>}
                                {shouldShowYearView.value && <button class="btn btn-link" onClick={navigateToCurrentYear}>今年</button>}
                            </div>
                        </div>
                    </div>
                    {
                        shouldShowSecondCalendar.value &&
                        <div class="f-datepicker-content">
                            {renderNavBar(true, secondaryCalendarNavBarProps.value)}
                            {renderCalender(true, secondaryCalendarProps.value)}
                            {selectingSecondaryMonth.value && renderMonth(true, secondMonthProps.value)}
                            {selectingSecondaryYear.value && renderYear(true, secondYearProps.value)}
                        </div>
                    }
                </div>
            );
        };
    }
});
